"""
下载指定版本的Python安装包，支持断点续传和下载进度显示，并校验文件完整性。
支持Windows、Linux和macOS平台的安装包下载。
1.基本用法
    # 列出所有可用版本
    python main.py --list

    # 下载特定版本 (所有平台)
    python main.py --version 3.8.10

    # 下载特定平台
    python main.py --version 3.9.13 --platform linux

    # 指定保存目录
    python main.py --version 3.10.6 --dir /path/to/save

2.高级用法
    # 批量下载多个版本
    for version in 3.7.9 3.8.10 3.9.13; do
        python main.py --version $version
    done

    # 仅下载Windows最新版本
    python main.py --version $(python main.py --list | head -1) --platform windows
"""

import os
import asyncio
import argparse
import time
from dotenv import load_dotenv
from pathlib import Path
from loguru import logger

logger.remove()
logger.info("启动 Python 版本下载器...")
ROOT = Path(__file__).parent.resolve()
os.chdir(ROOT)
logger.info(f"工作目录: {ROOT}")
# 加载环境变量
env = ROOT.joinpath('config', '.env')
# 修改工作目录，确保.env文件存在
env.touch(exist_ok=True)
logger.debug(f"加载环境变量文件: {env}")
load_result = load_dotenv(env)
if not load_result:
    logger.warning(f"环境文件加载异常: {env}, 使用默认配置")
    raise FileNotFoundError(f"环境文件加载异常: {env}, 使用默认配置")

# 加载帮助文本
HELP_TEXT = os.getenv('HELP_TEXT')
with open(ROOT / 'config' / HELP_TEXT, 'r', encoding='utf-8') as f:
    HELP_TEXT = f.read()

# 版本缓存文件路径
VERSION_CACHE_FILE = ROOT.joinpath(
    'cache', 'system', os.getenv('VERSION_CACHE_FILE', 'python_versions_cache.json')
)
# 更新全局缓存文件路径
os.environ['VERSION_CACHE_FILE'] = str(VERSION_CACHE_FILE)
logger.debug(f"版本缓存文件: {os.getenv('VERSION_CACHE_FILE')}")

# 支持的平台
PLATFORM_MAP = os.getenv('SUPPORTED_PLATFORMS')
if not PLATFORM_MAP:
    raise ValueError("环境变量 'SUPPORTED_PLATFORMS' 未设置")
PLATFORM_MAP = {p.lower() for p in PLATFORM_MAP.split(' ')}

# 下载文件存放路径
SAVE_DIR = ROOT / os.getenv('DOWNLOAD_DIR', 'packages')
if not os.path.isabs(SAVE_DIR):
    SAVE_DIR = ROOT.joinpath(SAVE_DIR)
os.makedirs(SAVE_DIR, exist_ok=True)
logger.debug(f"下载文件保存目录: {SAVE_DIR}")

# 日志文件路径
LOG_FILE = ROOT.joinpath('cache', 'logs', 'downloader.logs')
logger.add(LOG_FILE, rotation="10 MB", retention="5 days", encoding='utf8')
# 修改控制台输出日志级别

from src.script.download import download_python_version
from src.script.version import get_python_versions
from src.script.verify import validate_platform, validate_versions


def command():
    """检查命令行参数"""
    # 创建参数解析器
    parser = argparse.ArgumentParser(
        description='Python版本下载器',
        add_help=False,  # 禁用默认的help选项
        formatter_class=argparse.RawTextHelpFormatter
    )

    # 添加参数
    parser.add_argument('--version', nargs='*', help='指定一个或多个Python版本')
    parser.add_argument('--platform', choices=['all', 'windows', 'linux', 'macos'],
                        default='all', help='下载平台 (默认: all)')
    parser.add_argument('--dir', help='保存目录 (默认: packages)')
    parser.add_argument('--list', action='store_true', help='列出所有可用版本')
    parser.add_argument('--all', action='store_true', help='下载所有版本的所有平台安装包')
    parser.add_argument('--force', action='store_true', help='强制刷新版本缓存')
    parser.add_argument('--help', action='store_true', help='显示帮助信息')

    # 处理参数
    args, unknown = parser.parse_known_args()
    return args, unknown


def main():
    """主函数"""
    args, unknown = command()
    # 处理未知参数或--help
    if unknown or args.help:
        print(HELP_TEXT)
        return

    # 强制刷新缓存
    if args.force and os.path.exists(VERSION_CACHE_FILE):
        os.remove(VERSION_CACHE_FILE)

    # 处理--list参数
    if args.list:
        logger.info("获取所有可用版本...")
        versions = asyncio.run(get_python_versions())
        if versions:
            print("\n可用Python版本:")
            for s, v in versions.items():
                print(f"  - {s}:{v}")
        else:
            print("无法获取版本列表，请尝试 --force 刷新缓存")
        return

    # 验证参数
    if not args.version and not args.all:
        print("错误: 请指定要下载的版本或使用 --all 下载所有版本")
        print("使用 --help 查看帮助信息")
        return

    # 验证目录
    if args.dir:
        if not os.path.exists(args.dir):
            os.makedirs(args.dir, exist_ok=True)
        if not os.access(args.dir, os.W_OK):
            print(f"错误: 目录 {args.dir} 不可写")
            return

    # 获取所有可用版本
    all_versions = asyncio.run(get_python_versions())
    if not all_versions:
        print("无法获取版本列表，请尝试 --force 刷新缓存")
        return
    all_versions_set = all_versions.popitem()[1]
    for other_versions in all_versions.values():
        all_versions_set.union(other_versions)
    # 确定要下载的版本
    versions_to_download = []
    if args.all:
        versions_to_download = all_versions_set
        print(f"准备下载所有 {len(versions_to_download)} 个版本")
    elif args.version:
        # 验证每个版本是否有效
        versions_to_download = validate_versions(args.version, all_versions_set)
        if not versions_to_download:
            print(f"输入版本号异常: {';'.join(args.version)}, 请使用 --list 查看所有可用版本")
            return

    print(f"准备下载 {len(versions_to_download)} 个版本")
    # 依次下载每个版本
    total_success = True
    failed_versions = []
    for version in versions_to_download:
        print(f"\n{'=' * 40}")
        print(f"开始下载 Python {version} ({args.platform}平台)")
        print(f"{'=' * 40}")
        # 验证平台参数
        valid_platform = validate_platform(args.platform, PLATFORM_MAP)
        if not valid_platform:
            print(f"错误: 输出无效平台 {args.platform}")
            return
        # 执行下载
        success = asyncio.run(download_python_version(
            version=version,
            platforms=valid_platform,
            save_dir=args.dir if args.dir else SAVE_DIR
        ))

        if not success:
            total_success = False
            failed_versions.append(version)
            print(f"警告: 版本 {version} 下载失败")

    # 最终结果
    print("\n" + "=" * 40)
    if total_success:
        print(f"✅ 所有 {len(versions_to_download)} 个版本下载完成!")
    else:
        print(f"❌ 部分版本下载失败，请检查日志, 下载失败版本: {';'.join(failed_versions)}")


def run_main():
    """带有全局异常处理的主函数"""
    try:
        main()
    except KeyboardInterrupt:
        print("\n操作已取消")
    except Exception as e:
        logger.error(f"发生未预期错误: {str(e)}")
        print("请报告此问题或使用 --help 查看帮助信息")
        # 记录错误日志
        with open(ROOT.joinpath('cache', 'logs', 'downloader_error.log'), 'a', encoding='utf8') as f:
            import traceback
            f.write(f"{time.ctime()} - 错误:\n")
            traceback.print_exc(file=f)


if __name__ == '__main__':
    main()
